package pl.diagnoser.server.persistance.dao;

import java.awt.Desktop;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.Set;

import pl.diagnoser.client.dto.DefectDictDTO;
import pl.diagnoser.client.dto.DiagnoserResultDTO;
import pl.diagnoser.client.dto.DiagnoserResultsDTO;
import pl.diagnoser.client.dto.ObjectsDTO;
import pl.diagnoser.client.dto.SymptomDTO;
import pl.diagnoser.client.formulas.DiagnoserHBFormula;
import pl.diagnoser.client.formulas.DiagnoserIFormula;
import pl.diagnoser.client.formulas.DiagnoserSFormula;
import pl.diagnoser.client.formulas.DiagnoserVFormula;
import pl.diagnoser.client.tools.SearchObjectAttribute;
import pl.diagnoser.server.lpr.DiagnoserCore;
import pl.diagnoser.server.lpr.DiagnoserAttributes;
import pl.diagnoser.server.lpr.DiagnoserKnowledgeBase;
import pl.diagnoser.server.lpr.DiagnoserMachineLearning;

import lprlibrary.formula.Implication;
import lprlibrary.io.FormulaParser;
import lprlibrary.io.SimpleFileDataManager;
import lprlibrary.lpr.KnowledgeBase;
import lprlibrary.ml.MLResults;
import lprlibrary.ml.Samples;
import lprlibrary.ml.aq.AQ;

public class DiagnoserDao implements Serializable {
	
	private static final long serialVersionUID = 1L;
	
	public List<DiagnoserResultDTO> getPossibleDefects( List<SearchObjectAttribute> searchCriteria, List<SearchObjectAttribute> emptySearchCriteria, String path, boolean fast ) {
		DiagnoserCore diagnoser = null;
		try {
			diagnoser = DiagnoserCore.getInstance(new FileInputStream(path));
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		
		if(diagnoser != null)
			return diagnoser.getPossibleDefects(searchCriteria, emptySearchCriteria, fast);
		else
			return null;
	}
	
	public List<DefectDictDTO> getPossibleDefects( ObjectsDTO object, List<SymptomDTO> symptoms, String path ) {
        DiagnoserCore diagnoser = null;
        try {
                diagnoser = DiagnoserCore.getInstance(new FileInputStream(path));
        } catch (FileNotFoundException e) {
                e.printStackTrace();
        }
        
        if(diagnoser != null)
                return diagnoser.getPossibleDefects(object, symptoms);
        else
                return null;
	}
	
	public List<DiagnoserResultsDTO> getLearnResult( Integer mode, Double slider, String path ) {
        
        MLResults results = null;
        DiagnoserAttributes attributes = new DiagnoserAttributes();
        DiagnoserMachineLearning ml = null;
        try {
                ml = new DiagnoserMachineLearning(attributes, path);
        } catch (FileNotFoundException e) {
                e.printStackTrace();
        }
        
        if(ml != null) {
                ml.fillSamples(new EstimateDao().getEstimateForObjects(null), mode);
                Samples samples = ml.getSamples();
                Samples learnSamples = samples.getSubsetFromBeginingSamples(slider);
                Samples testSamples = samples.getSubsetFromEndingSamples(1.0-slider);
                AQ aq = new AQ();
                try {
                        aq.buildClassifier(learnSamples);
                } catch (Exception e) {
                        e.printStackTrace();
                }
                aq.testClassifier(testSamples);
                Implication[] imp = aq.getImplications();
                results = new MLResults(ml.getKnowledgeBase().getDefectWithImplications(), imp);
                ArrayList<DiagnoserResultsDTO> diagnoserResults = new ArrayList<DiagnoserResultsDTO>();
                
                Set<Implication> implications = results.getImplicationsMap().keySet();
                int i = 0;
                for(Implication implication: implications) {
                        i++;
                        diagnoserResults.add(new DiagnoserResultsDTO(i, 
                                        implication.toString(), 
                                        implication.getStrength(),
                                        results.getImplicationsMap().get(implication)));
                }
                
                return diagnoserResults;
        }
        
        return null;
	}
	
	private String getPropertyValue(Properties prop, String value) {
		
		if(value == null)
			return null;
		
		String ret = null;
		String oldValue = value;
		
		try {
			ret = new String(prop.getProperty(value).getBytes("ISO-8859-1"), "UTF-8");
		} catch (Exception e) {
			//System.out.println("Dla wartości: " + value + " brak danych z pliku properties;");
		}
		if(ret == null && oldValue != null)
			ret = oldValue;
		
		return ret;
	}
	
	public List<DiagnoserHBFormula> getHBFormulas(String path, String pathOrg) {
		DiagnoserCore diagnoser = null;
		try {
			diagnoser = DiagnoserCore.getInstance(new FileInputStream(path));
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		
		if(diagnoser != null) {
			diagnoser.getPossibleDefects(null, null, true);
			DiagnoserKnowledgeBase knowledgeBase = diagnoser.getKnowledgeBase();
			List<DiagnoserHBFormula> tmpList = new ArrayList<DiagnoserHBFormula>(knowledgeBase.getHBFormulas().size());
			Properties prop = new Properties();
	    	try {
				prop.load(new FileInputStream(pathOrg));
				for(DiagnoserHBFormula formula : knowledgeBase.getHBFormulas()) {
					formula.setContext(getPropertyValue(prop, formula.getContext()));
					formula.setDomination(getPropertyValue(prop, formula.getDomination()));
					formula.setObject1(getPropertyValue(prop, formula.getObject1()));
					formula.setObject2(getPropertyValue(prop, formula.getObject2()));
					formula.setType(getPropertyValue(prop, formula.getType()));
					formula.setTypicality(getPropertyValue(prop, formula.getTypicality()));
					tmpList.add(formula);
				}
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
	    	
			return tmpList;
		}
		return null;
	}
	
	public List<DiagnoserVFormula> getVFormulas(String path, String pathOrg) {
		
		DiagnoserCore diagnoser = null;
		try {
			diagnoser = DiagnoserCore.getInstance(new FileInputStream(path));
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		
		if(diagnoser != null) {
			diagnoser.getPossibleDefects(null, null, true);
			DiagnoserKnowledgeBase knowledgeBase = diagnoser.getKnowledgeBase();
			List<DiagnoserVFormula> tmpList = new ArrayList<DiagnoserVFormula>(knowledgeBase.getVFormulas().size());
			
			Properties prop = new Properties();
	    	try {
				prop.load(new FileInputStream(pathOrg));
				for(DiagnoserVFormula formula : knowledgeBase.getVFormulas()) {
					formula.setAttribute(getPropertyValue(prop, formula.getAttribute()));
					//formula.setConfidence(getPropertyValue(prop, formula.getConfidence()));
					formula.setConfidence(formula.getConfidence());
					formula.setObject(getPropertyValue(prop, formula.getObject()));
					formula.setValue(getPropertyValue(prop, formula.getValue()));
					tmpList.add(formula);
		    	}
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
			return tmpList;
		}
		return null;
	}
	
	public List<DiagnoserSFormula> getSFormulas(String path, String pathOrg) {
		
		DiagnoserCore diagnoser = null;
		try {
			diagnoser = DiagnoserCore.getInstance(new FileInputStream(path));
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		
		if(diagnoser != null) {
			diagnoser.getPossibleDefects(null, null, true);
			DiagnoserKnowledgeBase knowledgeBase = diagnoser.getKnowledgeBase();
			
			List<DiagnoserSFormula> tmpList = new ArrayList<DiagnoserSFormula>(knowledgeBase.getSFormulas().size());
			
			Properties prop = new Properties();
	    	try {
				prop.load(new FileInputStream(pathOrg));
				for(DiagnoserSFormula formula : knowledgeBase.getSFormulas()) {
		    		formula.setContext(getPropertyValue(prop, formula.getContext()));
		    		formula.setObject1(getPropertyValue(prop, formula.getObject1()));
		    		formula.setObject2(getPropertyValue(prop, formula.getObject2()));
		    		//formula.setRate(getPropertyValue(prop, formula.getRate()));
		    		formula.setRate(formula.getRate());
		    		tmpList.add(formula);
		    	}
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
	    	return tmpList;
		}
		return null;
	}
	
	public List<DiagnoserIFormula> getIFormulas(String path, String pathOrg) {
		
		DiagnoserCore diagnoser = null;
		try {
			diagnoser = DiagnoserCore.getInstance(new FileInputStream(path));
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		
		if(diagnoser != null) {
			diagnoser.getPossibleDefects(null, null, true);
			DiagnoserKnowledgeBase knowledgeBase = diagnoser.getKnowledgeBase();
			
			List<DiagnoserIFormula> tmpList = new ArrayList<DiagnoserIFormula>(knowledgeBase.getIFormulas().size());
			
			Properties prop = new Properties();
	    	try {
				prop.load(new FileInputStream(pathOrg));
				for(DiagnoserIFormula formula : knowledgeBase.getIFormulas()) {
		    		//formula.setConclusion(getPropertyValue(prop, formula.getConclusion()));
		    		//formula.setStrength(getPropertyValue(prop, formula.getStrength()));
					formula.setConclusion(formula.getConclusion());
		    		formula.setStrength(formula.getStrength());
		    		
		    		List<String> tmpNewPremises = new ArrayList<String>(formula.getPremises().size());
		    		for(String tmpPremises : formula.getPremises()) {
		    			//if(prop.getProperty(tmpPremises) != null) { 
		    				tmpNewPremises.add(getPropertyValue(prop, tmpPremises));
		    			//}
		    		}
		    		
		    		
		    		formula.setPremises(tmpNewPremises);
		    		tmpList.add(formula);
		    	}
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
	    	return tmpList;
		}
		return null;
	}
	
	public String saveImplication(List<String> implications, String path) {
		String ret = "";
		KnowledgeBase knowledgeBase = new DiagnoserKnowledgeBase();
		SimpleFileDataManager dataManager = new SimpleFileDataManager(knowledgeBase);
		FormulaParser parser = new FormulaParser();
		try {
			dataManager.setSourceFile(new FileInputStream( path ));
			dataManager.load();
			List<Implication> baseImplications = knowledgeBase.getFormulasI();
			for(String implication : implications) {
				int flag = 0;
				Implication imp = parser.makeImplication(implication);
				for(Implication baseImp: baseImplications) {
					if (imp.isEqual(baseImp)) {
						baseImp.setStrength(imp.getStrength());
						flag = 1;
					}
				}
				if (flag==0) {
					baseImplications.add(imp);
				}
			}
			knowledgeBase.setFormulasI(baseImplications);
			dataManager.setDestinationFile(new FileOutputStream( path ));
			dataManager.save();
			ret = "OK";
		} catch (Exception e) {
			ret = e.getMessage();
		}
		
		return ret;
	}
	
	public String openPdfFile(String fileName, String path) {
		String info = "OK";
		try {
			File pdfFile = new File(path + fileName + ".pdf");
			if (pdfFile.exists()) {
				if (Desktop.isDesktopSupported())
					Desktop.getDesktop().open(pdfFile);
				else
					info = "Awt Desktop is not supported!";
			} else
				info = "Na serwerze brak pliku dla artykułu: " + fileName;
		} catch(Exception e) {
			info = e.getMessage();
		}
		
		return info;
	}
}